package com.sc.core.make.file;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.sc.core.make.MasterMake;
import com.sc.core.make.build.*;
import com.sc.core.make.dto.MakeInfoDTO;
import com.sc.core.make.dto.MakeJoinTableDTO;
import com.sc.core.make.enums.ClassType;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.io.File;
import java.nio.file.Files;
import java.util.List;

@Log4j2
public class Mapper implements IFileMake{
    private final MakeInfoDTO makeInfo;
    private final List<MakeJoinTableDTO> makeJoinTables;

    @Getter
    private String message = "成功";

    public Mapper(MakeInfoDTO makeInfo, List<MakeJoinTableDTO> makeJoinTables) {
        this.makeInfo = makeInfo;
        this.makeJoinTables = makeJoinTables;
    }

    @Override
    public IFileMake make() {
        String mapperName = makeInfo.getClassname() + "Mapper";
        ClassBuild classBuild = new ClassBuild(mapperName, ClassType.INTERFACE);

        classBuild.setPackageName(makeInfo.getPackageName() + ".mapper");
        classBuild.addImportClass(BaseMapper.class);
        classBuild.addImportClass(org.apache.ibatis.annotations.Mapper.class);
        classBuild.addImportClass(makeInfo.getPackageName() + "." + makeInfo.getClassname() + "Entity");
        classBuild.setExtendClass(new GenericTypeBuild(BaseMapper.class).addGeneric(
                new GenericTypeBuild(makeInfo.getClassname() + "Entity")
        ));
        classBuild.addAnnotationClass(new AnnotationBuild(org.apache.ibatis.annotations.Mapper.class));
        classBuild.setDocument(new String[]{makeInfo.getTableComment() + " Mapper"});

        makeMethodGetList(classBuild, true);
        makeMethodGetList(classBuild, false);

        String filepath = MasterMake.getMakeDir(makeInfo.getModuleName()) + File.separator + "mapper" + File.separator + mapperName + ".java";

        message = MasterMake.writeFile(filepath, classBuild.toString());

        return this;
    }

    private void makeMethodGetList(ClassBuild classBuild, boolean isCount) {
        MethodBuild   methodBuild = new MethodBuild(isCount ? "getDefaultListCount" : "getDefaultList");
        StringBuilder sql         = new StringBuilder();
        StringBuilder fields      = new StringBuilder();

        fields.append("a.*");
        sql.append("\"SELECT %s \"")
           .append(MasterMake.retraction(MasterMake.BR, 3))
           .append(" + ")
           .append("\" FROM ").append(makeInfo.getTableName()).append(" AS a\"");
        makeJoinTables.forEach(makeJoinTableDTO -> {
            sql.append(MasterMake.retraction(MasterMake.BR, 3))
               .append(" + ")
               .append(String.format("\" LEFT JOIN %s AS %s ON a.%s = %2$s.%s\"",
                    makeJoinTableDTO.getTableName(),
                    makeJoinTableDTO.getTableAlias(),
                    makeJoinTableDTO.getForeignKey(),
                    makeJoinTableDTO.getPrimaryKey()
            ));
            fields.append(String.format(", %s.%s AS %1$s_%2$s", makeJoinTableDTO.getTableAlias(), makeJoinTableDTO.getShowField()));
        });
        sql.append(MasterMake.retraction(MasterMake.BR, 3)).append(" + ");
        sql.append("\" ${ew.customSqlSegment}");
        sql.append(isCount ? "\"" : " ${limitInfo}\"");

        AnnotationBuild annotationBuild = new AnnotationBuild(Select.class);
        annotationBuild.addParam("value", new ReferValue(String.format(sql.toString(), isCount ? "COUNT(*)" :fields)));
        methodBuild.addAnnotation(annotationBuild);

        MethodParamBuild wrapper = new MethodParamBuild("wrapper", new GenericTypeBuild(Wrapper.class).addGeneric(new GenericTypeBuild("?")));
        wrapper.addAnnotation(new AnnotationBuild(Param.class).addParam("value", new ReferValue("Constants.WRAPPER")));
        methodBuild.addMethodParam(wrapper);

        if (isCount) {
            methodBuild.setReturnType(new GenericTypeBuild(Long.class));
        }else{
            methodBuild.addMethodParam(new MethodParamBuild("limitInfo", new GenericTypeBuild(String.class)));
            methodBuild.setReturnType(new GenericTypeBuild(List.class).addGeneric(new GenericTypeBuild(makeInfo.getClassname() + "Entity")));
        }

        classBuild.addMethod(methodBuild);
        classBuild.addImportClass(Select.class);
        classBuild.addImportClass(Param.class);
        classBuild.addImportClass(List.class);
        classBuild.addImportClass(Constants.class);
        classBuild.addImportClass(Wrapper.class);
    }
}
